package com.wave.system.util;


import com.serotonin.modbus4j.exception.ModbusInitException;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import io.netty.buffer.ByteBufUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
public class RFIDReaderWriterUtil {
    // RFID读写器 读取芯片epc区的货架编号起始寄存器地址
    private static final String REGISTER_ADDRESS = "0018";
    // RFID读写器 写入芯片user区的产品编号集合起始寄存器地址
    private static final String REGISTER_ADDRESS_USER = "0016";
    // RFID读写器 读取数据时的寄存器数量(11个)
    private static final String REGISTER_NUM = "0008";
    // RFID读写器 写入数据时的前缀
    private static final String HEX_PRE = "00B20000";
    // RFID读写器 写入数据时的设备地址（00）+modbus功能码（10）
    private static final String HEX_MIDDLE = "0010";

    public static void main(String[] args) throws IOException, ModbusInitException, ModbusTransportException, InterruptedException {
        //writeRFID("192.168.150.201","010422DM6S40938126-3-F");
        //System.out.println(readRFID("192.168.150.201"));
        /*System.out.println(getHex("abcdefghijklmnopqrstuvwxyz"));*/

        List<String> snCodes = new ArrayList<>();
        /*snCodes.add("2DM6S40938126");
        snCodes.add("2DM6S40938126");
        snCodes.add("2DM6S40938126");
        snCodes.add("2DM6S40938126");
        snCodes.add("2DM6S40938126");
        snCodes.add("2DM6S40938126");*/

        /*snCodes.add("2DM6S3");
        snCodes.add("2DM6S4");
        snCodes.add("2DM6S5");
        snCodes.add("2DM6S6");
        snCodes.add("2DM6S7");
        snCodes.add("2DM6S8");

        String join = String.join(",", snCodes);
        System.out.println(join);
        System.out.println(join.length());
        //writeRFID("192.168.150.205", join);*/
        //System.out.println(readRFID("192.168.150.203"));


        Socket socket = new Socket("192.168.150.10", 502);
        System.out.println();


    }

    /**
     * RFID读写器 写入数据
     *
     * @param ip   ip地址
     * @param data 需要写入的数据
     * @return true：写入成功，false：写入失败
     * @throws IOException
     */
    private static boolean writeRFIDNext(String ip, String data) {
        Socket socket = null;
        boolean result = false;
        try {
            if (StringUtils.isBlank(data)) {
                return false;
            }
            if (data.length() % 2 != 0) {//如果不是偶数，最后加一个0
                data = data + "0";
            }
            socket = new Socket(ip, 502);
            OutputStream outputStream = socket.getOutputStream();

            // RFID读写器 写入数据时成功时的返回标志
            Map<String, String> writeSuccessMap = new HashMap<>();
            //获取16进制字符串
            String hexStr = getHex(data, ip, writeSuccessMap);
            byte[] hexBytes = ByteBufUtil.decodeHexDump(hexStr);
            outputStream.write(hexBytes);
            InputStream inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int read = inputStream.read(bytes);
            String hexResult = ByteBufUtil.hexDump(bytes, 0, read);
            log.info("RFID读写器写入后返回的原始结果:{}", hexResult);
            if (StringUtils.isNotBlank(hexResult) && hexResult.equalsIgnoreCase(writeSuccessMap.get("success" + ip))) {
                log.info("RFID读写器：{}，写入数据成功：[字符串：{},转为十六进制：{}]", ip, data, hexStr);
                result = true;
            } else {
                log.info("RFID读写器：{}，写入数据失败：[字符串：{},转为十六进制：{}]", ip, data, hexStr);
            }
        } catch (Exception e) {
            log.info("RFID读写器写入数据报错,ip地址为：{}，报错信息为：{}", ip, e.getMessage());
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    log.info("关闭RFID读写器socket：{}失败，报错信息为：{}", ip, e.getMessage());
                }
            }
        }
        return result;
    }

    /**
     * 获取转为16进制的字符串
     *
     * @param str             原始字符串
     * @param ip              RFID的ip地址
     * @param writeSuccessMap 写入成功的返回标志
     */
    private static String getHex(String str, String ip, Map<String, String> writeSuccessMap) {
        String hexStr = ByteBufUtil.hexDump(str.getBytes());//转出16进制字符串
        String s0 = StringUtils.leftPad(Integer.toHexString(7 + hexStr.length() / 2), 4, "0");//后面所有的字节数
        String s1 = StringUtils.leftPad(Integer.toHexString((hexStr.length() / 4) == 0 ? 1 : (hexStr.length() / 4)), 4, "0");//寄存器数量
        String s2 = StringUtils.leftPad(Integer.toHexString(hexStr.length() / 2), 2, "0");//数据内容字节数
        writeSuccessMap.put("success" + ip, HEX_PRE + "0006"/*代表后面6个字节*/ + HEX_MIDDLE + REGISTER_ADDRESS_USER + s1);
        return HEX_PRE + s0 + HEX_MIDDLE + REGISTER_ADDRESS_USER + s1 + s2 + hexStr;
    }


    /**
     * 读写rfid时的前置操作，读的时候type传1，写产品编号sn码的时候type传3
     * type=1时读区域改成epc区(货架编号DK....在epc区)，type=3时读区域改成user区(产品编号sn码在user区)
     *
     * @param ip
     * @param type
     * @return
     */
    private static boolean rwRFIDPre(String ip, int type) {
        Socket socket = null;
        try {
            socket = new Socket(ip, 502);
            OutputStream outputStream = socket.getOutputStream();
            //寄存器地址为2的值改成0001就是（epc区），寄存器地址为2的值为就是0003（user区），默认user区
            if (type == 1) {
                outputStream.write(ByteBufUtil.decodeHexDump("00F900000009001000020001020001"));//更改读区域为epc区
            }
            if (type == 3) {
                outputStream.write(ByteBufUtil.decodeHexDump("00F900000009001000020001020003"));//更改读区域为user区
            }
            InputStream inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int read = inputStream.read(bytes);
            String result = ByteBufUtil.hexDump(bytes, 0, read);
            if (StringUtils.isNotBlank(result) && "00F900000006001000020001".equalsIgnoreCase(result)) {
                return true;
            }
        } catch (IOException e) {
            log.info("RFID读写器把读区域改成epc区/user区报错,ip地址为：{}，type={}，报错信息为：{}", ip, type, e.getMessage());
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    log.info("关闭RFID读写器socket：{}失败，报错信息为：{}", ip, e.getMessage());
                }
            }
        }
        return false;
    }

    /**
     * rfid读取卡片信息
     *
     * @param ip rfid的ip地址
     * @return 卡片信息
     */
    private static String readRFIDNext(String ip) throws InterruptedException {
        Socket socket = null;
        String result = "";
        try {
            socket = new Socket(ip, 502);
            OutputStream outputStream = socket.getOutputStream();
            outputStream.write(ByteBufUtil.decodeHexDump("00B1000000060003" + REGISTER_ADDRESS + REGISTER_NUM));//读标签数据
            InputStream inputStream = socket.getInputStream();
            byte[] bytes = new byte[1024];
            int read = inputStream.read(bytes);
            result = ByteBufUtil.hexDump(bytes, 0, read);
            //log.info("RFID读写器：{}，读数据:{}", ip, result);
            if (StringUtils.isNotBlank(result) && result.length() > 18) {
                result = result.substring(18);
                return new String(ByteBufUtil.decodeHexDump(result));
            } else {
                log.info("RFID读写器读数据失败，ip地址为：{}，返回结果为：{}", ip, result);
            }
        } catch (IOException e) {
            log.info("RFID读写器读数据报错,ip地址为：{}，报错信息为：{}", ip, e.getMessage());
            return null;
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    log.info("关闭RFID读写器socket：{}失败，报错信息为：{}", ip, e.getMessage());
                }
            }
        }
        return null;
    }

    /**
     * rfid读取卡片epc区信息
     *
     * @param ip rfid的ip地址
     * @return 卡片信息
     */
    public static String readRFID(String ip) throws InterruptedException {
        int i = 0;
        while (i < 3) {
            i++;
            if (rwRFIDPre(ip, 1)) break;
            TimeUnit.SECONDS.sleep(1);
        }

        i = 0;
        while (i < 3) {
            i++;
            String result = readRFIDNext(ip);
            if (StringUtils.isNotBlank(result)) {
                if (result.length() > 15) {
                    result = result.substring(0, result.length() - 1);
                }
                return result;
            }
            TimeUnit.SECONDS.sleep(1);
        }
        return null;
    }

    /**
     * rfid往芯片user区写入产品编号sn码集合信息
     *
     * @param ip rfid的ip地址
     * @return 卡片信息
     */
    public static boolean writeRFID(String ip, String data) throws InterruptedException {
        int i = 0;
        while (i < 3) {
            i++;
            if (rwRFIDPre(ip, 3)) break;
            TimeUnit.SECONDS.sleep(1);
        }

        i = 0;
        while (i < 3) {
            i++;
            if (writeRFIDNext(ip, data)) return true;
            TimeUnit.SECONDS.sleep(1);
        }
        return false;
    }

}
